package com.biubiux2;

import com.biubiux2.client.Client;
import com.biubiux2.message.MessageType;
import com.biubiux2.message.MessageUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;

/**
 * @author noexcs
 * @since 8/10/2022 7:55 PM
 */
@Slf4j
public class ConnectionManager extends SimpleChannelInboundHandler<ByteBuf> {

    Robot robot;

    public ConnectionManager(Robot robot) {
        this.robot = robot;
    }

    private Channel channel;

    public String getSessionId() {
        return sessionId;
    }

    public void setSessionId(String sessionId) {
        this.sessionId = sessionId;
    }

    private volatile String sessionId;

    private CountDownLatch loggedIn = new CountDownLatch(1);

    private volatile boolean logged = false;

    private volatile boolean connected = false;

    private int userId;

    private String password;

    public void connect(String host, int port) {
        channel = Client.run(host, port, this);
        synchronized (this) {
            connected = true;
            notifyAll();
        }
    }

    public void login(int userId, String password) {
        this.userId = userId;
        this.password = password;
        channel.writeAndFlush(MessageUtil.createLoginMsg(userId, password));
        try {
            loggedIn.await();
        } catch (InterruptedException ignored) {
        }
    }

    public void logout() {
        if (channel != null && logged) {
            channel.writeAndFlush(MessageUtil.createLogoutMsg());
            logged = false;
        }
    }

    public void closeConnection() {
        try {
            if (channel != null) {
                channel.close().sync();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        log.debug("连接已断开");
        connected = false;
//        reconnect();
    }

    public void reconnect() {
        log.debug("尝试重连");
        for (int i = 0; i < 5; i++) {
            try {
                channel = Client.run("localhost", 8808, this);
                break;
            } catch (Exception ignored) { }
        }
        if (sessionId != null) {
            channel.writeAndFlush(MessageUtil.createReconnectMsg(sessionId));
        } else {
            logged = false;
            login(userId, password);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        int type = msg.readInt();

        if (type == MessageType.USER_MSG) {
            // 用户对话消息
            int senderUserId = msg.readInt();
            int receiverUserId = msg.readInt();
            byte[] contentBytes = new byte[msg.readableBytes()];
            msg.readBytes(contentBytes);
            String content = new String(contentBytes, StandardCharsets.UTF_8);
            if (receiverUserId == 0) {
                robot.readBroadcast(content, senderUserId);
            } else {
                robot.readPrivate(content, senderUserId);
            }
        } else if (type == MessageType.LOGIN_RESPONSE) {
            // 登录成功消息
            robot.loginCompletion();
            synchronized (this) {
                logged = true;
                notifyAll();
            }
            byte[] bytes = new byte[msg.readableBytes()];
            msg.readBytes(bytes);
            sessionId = new String(bytes, StandardCharsets.UTF_8);
            log.debug("Session Id:{}", sessionId);
            loggedIn.countDown();
        } else if (type == MessageType.RELOGIN) {
            // 重复登录消息
            log.debug("重复登录");
            channel.close().sync();
        } else if (type == MessageType.RECONNECT_SUCCESS_RESPONSE) {
            // 重连成功消息
            log.debug("重连成功");
            synchronized (this) {
                connected = true;
                notifyAll();
            }
        } else if (type == MessageType.RECONNECT_FAIL_RESPONSE) {
            // 重连失败消息
            connected = true;
            logged = false;
            login(userId, password);
        }
    }

    public void sendPrivate(String content, int receiverUserId) {
        while (!connected || !logged) {
            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException ignored) {
                }
            }
        }
        ByteBuf privateMsg = MessageUtil.createSendMsg(userId, receiverUserId, content);
        channel.writeAndFlush(privateMsg);
    }

    public void sendBroadcast(String content) {
        while (!connected || !logged) {
            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException ignored) {
                }
            }
        }
        ByteBuf broadcastMsg = MessageUtil.createSendMsg(userId, 0, content);
        channel.writeAndFlush(broadcastMsg);
    }
}
